"""数据的预处理是数据分析，或者机器学习训练前的重要步骤。
通过数据预处理，可以

提高数据质量，处理数据的缺失值、异常值和重复值等问题，增加数据的准确性和可靠性
整合不同数据，数据的来源和结构可能多种多样，分析和训练前要整合成一个数据集
提高数据性能，对数据的值进行变换，规约等（比如无量纲化），让算法更加高效
本篇介绍的分类编码处理，主要用于将类别型数据转换为可以用于分析或机器学习的形式。
类别型数据是指具有离散、不连续取值的数据，例如性别（男/女）、等级（优/良/中/差）之类数据。
对这些数据进行适当的编码，可以提高数据处理效率和准确度。

1. 原理
分类编码的原理比较简单，常用的两种是顺序编码和独热编码。

1.1. 顺序编码
顺序编码很好理解，就是按照顺序给离散的数据编码，比如下面成绩和班级信息的数据："""
from sklearn import preprocessing as pp
import numpy as np

data = np.array(
    [
        ["优", "三班"],
        ["及格", "二班"],
        ["良", "一班"],
        ["优", "五班"],
        ["中", "八班"],
        ["良", "六班"],
        ["不及格", "三班"],
        ["优", "十班"],
    ]
)
"""原始数据是用中文描述的，无法直接用于机器学习算法之中，所以要编码。
scikit-learn库的OrdinalEncoder就是用来顺序编码的。
"""

data = np.array(
    [
        ["优", "三班"],
        ["及格", "二班"],
        ["良", "一班"],
        ["优", "五班"],
        ["中", "八班"],
        ["良", "六班"],
        ["不及格", "三班"],
        ["优", "十班"],
    ]
)
oen_c = pp.OrdinalEncoder()

# 顺序编码
oen_c.fit_transform(data)

"""# 运行结果
array([[2., 1.],
       [3., 2.],
       [4., 0.],
       [2., 3.],
       [1., 4.],
       [4., 5.],
       [0., 1.],
       [2., 6.]])
从运行结果可以看出，虽然"优", "良", "中"等成绩等级，"一班", "二班", "三班"等班级信息都被编码成顺序的数字。
但是，并不是按照中文含义的顺序来编码的，比如优对应2，及格对应3，三班对应1，二班却对应2等等。

为了让编码后的数字和原来的中文含义的顺序有对应，我们可以定义编码的顺序。"""

# 定义中文的顺序
catagories = [
    ["优", "良", "中", "及格", "不及格"],
    ["一班", "二班", "三班", "五班", "六班", "八班", "十班"],
]

oen_c = pp.OrdinalEncoder(categories=catagories)
oen_c.fit_transform(data)

"""# 运行结果
array([[0., 2.],
       [3., 1.],
       [1., 0.],
       [0., 3.],
       [2., 5.],
       [1., 4.],
       [4., 2.],
       [0., 6.]])
这样，编码后的数字的顺序就能和中文所代表的含义对应起来了。

1.2. 独热编码
上面示例中的成绩等级和班级信息都有顺序，如果对没有顺序含义的信息进行顺序编码的话，
就会赋予给信息添加了顺序的含义，对于后续算法的应用可能会产生影响。

这时，就可以用独热编码的方式来处理，比如对于下面的科目信息：

data = np.array([["语文"], ["数学"], ["英语"], ["物理"], ["化学"]])
这些科目信息之间是没有顺序概念的，语文不一定排在数学前面，化学也不一定要排在英语后面。
这时，用独热编码就比较合适了。"""

data = np.array([["语文"], ["数学"], ["英语"], ["物理"], ["化学"]])

enc = pp.OneHotEncoder()
enc.fit_transform(data).toarray()

"""# 运行结果
array([[0., 0., 0., 0., 1.],
       [0., 1., 0., 0., 0.],
       [0., 0., 0., 1., 0.],
       [0., 0., 1., 0., 0.],
       [1., 0., 0., 0., 0.]])
从中可以看出，语文编码成了数组[0., 0., 0., 0., 1.]，数学编码成了[0., 1., 0., 0., 0.]数组等等。
科目信息之间不存在顺序。

2. 作用
分类编码是数据挖掘和机器学习领域中非常重要的一个环节，主要的作用有：

转换数据格式：将类别型数据转换为数值型数据，从而使其能够被计算机处理和建模。
提高处理效率：分类编码可以将多个类别型变量转换为多个数值型变量，从而简化了数据处理过程，提高了数据处理效率。
提高性能：分类编码可以通过独热编码等方式，将类别型变量转换为多个二元特征，从而增加了模型的非线性能力和表达能力，从而提高了模型的性能。
降低复杂度：分类编码可以将多个类别型变量转换为多个数值型变量，从而降低了模型的复杂度。这有利于减少模型的过拟合，提高模型的泛化能力。
处理不平衡类别：分类编码可以通过生成额外的特征或者使用其他技术来处理不平衡类别的数据。
去除噪声和冗余特征：分类编码可以通过删除不相关或冗余的特征来减少数据的噪声和冗余，从而提高数据的质量和模型的性能。
3. 总结
本篇介绍了两种编码方式，顺序编码（OrdinalEncoder）和独热编码（OneHotEncoder），但scikit-learn库提供的编码方式并不只有这两种。

还有目标编码（TargetEncoder），标签编码（LabelEncoder）等等，可以参考官方文档中的使用方法，在合适的场景中使用。"""